package com.gzxx.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * ActivitiUtils
 *
 * @author chenjing
 */
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ActivitiUtils {

    private final TaskService taskService;
    private final HistoryService historyService;
    private final RepositoryService repositoryService;
    private final RuntimeService runtimeService;

    /**
     * 流程部署
     */
    private void deployProcess(String processDefinitionKey) {
        long count = ProcessEngines.getDefaultProcessEngine().getRepositoryService()
                .createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .count();//返回一个集合列表，封装流程定义
        if (count < 1) {
            Deployment deployment = repositoryService
                    .createDeployment()
                    // 禁用校验
                    .disableSchemaValidation()
                    .name("订单流程")
                    .addClasspathResource(processDefinitionKey + ".bpmn")
                    .deploy();
        }
    }

    /**
     * 创建一个流程实例（启动流程）
     *
     * @param key         流程定义key 不可为空
     * @param businessKey 标识唯一流程实例的键 业务key
     * @param variables   传递的参数
     */
    public ProcessInstance startProcessInstanceByKey(String key, String businessKey, Map<String, Object> variables) {
        ProcessInstance processInstance = queryProcessInstanceByBusinessKey(businessKey);
        if (processInstance != null) {
            return processInstance;
        }
        return runtimeService.startProcessInstanceByKey(key, businessKey, variables);
    }

    /**
     * 根据业务key查询流程
     */
    public ProcessInstance queryProcessInstanceByBusinessKey(String businessKey) {
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .singleResult();
        return processInstance;
    }

    /**
     * 根据业务key查询任务
     *
     * @param businessKey
     */
    public List<Task> queryTaskByBusinessKey(String businessKey) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).list();
        return tasks;
    }

    /**
     * 查询用户所有任务
     */
    public List<Task> queryTasksByUserId(String userId) {
        return taskService.createTaskQuery().taskAssignee(userId).list();
    }

    public List<Task> queryTaskByBusinessKeyAndTaskDefinitionKey(String businessKey, String taskDefinitionKey) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceBusinessKey(businessKey).taskDefinitionKey(taskDefinitionKey).list();
        return tasks;
    }

    /**
     * 查询用户所有任务 分页
     */
    private List<Task> queryTasksByUserId(String userId, String taskDefinitionKey, int page, int pageSize) {
        int firstResult = 0;
        int maxResult = pageSize;
        if (page > 1) {
            firstResult = (page - 1) * pageSize;
            maxResult = firstResult + pageSize;
        }
        return taskService.createTaskQuery()
                .taskAssignee(userId)
                .taskDefinitionKey(taskDefinitionKey)
                .orderByTaskCreateTime()
                .desc()
                .listPage(firstResult, maxResult);
    }

    /**
     * 查询用户某流程任务
     *
     * @param userId
     * @param businessKey
     * @return
     */
    public Task queryTaskByUserId(String userId, String businessKey) {
        List<Task> tasks = queryTaskByBusinessKey(businessKey);
        Task task = null;
        for (Task task1 : tasks) {
            if (task1.getAssignee().equals(userId)) {
                task = task1;
                continue;
            }
        }
        return task;
    }

    /**
     * 完成任务
     */
    @Transactional(rollbackFor = Exception.class)
    public void complete(String taskId, Map<String, Object> variables) {
        taskService.complete(taskId, variables);
    }

    /**
     * 完成任务 无参数
     */
    public void complete(String taskId) {
        taskService.complete(taskId);
    }

    /**
     * 结束流程
     *
     * @param processInstanceId 流程示例id
     */
    public void deleteProcessInstance(String processInstanceId, String msg) {
        runtimeService.deleteProcessInstance(processInstanceId, msg);
    }

    /**
     * 判断流程是否为该用户提交
     *
     * @param businessKey 业务流程key
     * @param userId      用户id
     */
    public boolean isProcessCommittedForUser(String businessKey, String userId) {
        List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .orderByTaskCreateTime()
                .asc()
                .list();
        String myTaskId = null;
        HistoricTaskInstance myTask = null;
        for (HistoricTaskInstance hti : htiList) {
            // 对比当前流程是否为该用户提交
            if (userId.equals(hti.getAssignee())) {
                myTaskId = hti.getId();
                myTask = hti;
                break;
            }
        }
        if (myTask != null && myTaskId != null) {
            return true;
        }
        return false;
    }


    /**
     * 通过流程定义id挂起流程
     */
    public void suspend(String businessKey) {
        ProcessInstance processInstance = queryProcessInstanceByBusinessKey(businessKey);
        boolean suspended = processInstance.isSuspended();
        String processInstanceId = processInstance.getProcessInstanceId();
        if (!suspended) {
            runtimeService.suspendProcessInstanceById(processInstanceId);
            log.info("流程实例ID为：{} 已挂起", processInstanceId);
        }
    }

    /**
     * 通过流程定义id激活流程
     */
    public void activate(String businessKey) {
        ProcessInstance processInstance = queryProcessInstanceByBusinessKey(businessKey);
        boolean suspended = processInstance.isSuspended();
        String processInstanceId = processInstance.getProcessInstanceId();
        if (suspended) {
            runtimeService.activateProcessInstanceById(processInstanceId);
            log.info("流程实例ID为：{}已激活", processInstanceId);
        }
    }

    /**
     * 任务转办
     *
     * @param taskId 任务id
     * @param userId 新用户
     */
    public void transferTask(String taskId, String userId) {
        taskService.setAssignee(taskId, userId);
    }


    /**
     * 工作流校验
     */
    public String checkProcess(String businessKey) {
        ProcessInstance processInstance = this.queryProcessInstanceByBusinessKey(businessKey);
        // 流程不存在
        if (processInstance == null) {
            return null;
        }
        // 被挂起
        if (processInstance.isSuspended()) {
            return null;
        }
        return processInstance.getProcessInstanceId();
    }

    public Set<String> getBusinessKeySet(Set<String> processDefinitionIdSet) {
        List<ProcessInstance> processInstances = runtimeService
                .createProcessInstanceQuery()
                .processDefinitionIds(processDefinitionIdSet)
                .list();
        if (ObjectUtils.isEmpty(processInstances)) {
            return null;
        }
        Set<String> businessKeySet = Sets.newHashSet();
        for (ProcessInstance processInstance : processInstances) {
            businessKeySet.add(processInstance.getBusinessKey());
        }
        return businessKeySet;
    }

    /**
     * 获取用户某节点总任务数
     */
    public long getUserTaskTotal(String userId, String taskDefinitionKey) {
        return taskService.createTaskQuery()
                .taskAssignee(userId)
                .taskDefinitionKey(taskDefinitionKey)
                .count();
    }

    /**
     * 获取用户流程定义key
     */
    public List<String> getBusinessKey(String userId) {
        List<Task> tasks = queryTasksByUserId(userId);
        Set<String> processDefinitionIdSet = Sets.newHashSet();
        for (Task task : tasks) {
            processDefinitionIdSet.add(task.getProcessDefinitionId());
        }
        if (ObjectUtils.isEmpty(processDefinitionIdSet)) {
            return null;
        }
        List<ProcessInstance> processInstances = runtimeService
                .createProcessInstanceQuery()
                .processDefinitionIds(processDefinitionIdSet)
                .list();
        Set<String> businessKeySet = Sets.newHashSet();
        for (ProcessInstance processInstance : processInstances) {
            businessKeySet.add(processInstance.getBusinessKey());
        }
        if (ObjectUtils.isEmpty(businessKeySet)) {
            return null;
        }
        return Lists.newArrayList(businessKeySet);
    }

    public <T> T getVariable(String taskId, String variableName, Class<T> clazz) {
        return taskService.getVariable(taskId, variableName, clazz);
    }

    public void removeVariable(Task task, String variableName) {
        taskService.removeVariable(task.getId(), variableName);
        runtimeService.removeVariable(task.getExecutionId(), variableName);
    }
}

